<?php

namespace nabu\controllers\blogController;

defined('NABU') || exit;

require_once 'libs/csrf.php';
require_once 'libs/validations.php';
require_once 'models/blogModel.php';
require_once 'libs/utils.php';
require_once 'libs/parsedown-1.7.4/Parsedown.php';

use nabu\libs\csrf\csrf,
    nabu\libs\validations\validations,
    nabu\models\blogModel\blogModel,
    nabu\libs\utils\utils,
    Parsedown\Parsedown;

// Administra el flujo de datos de los artículos.
class blogController {
  private const num_articles = 9;

  private static function default_route() {
    $GLOBALS['messages'] -> redirect(NABU_ROUTES['home']);
  }

  // Renderiza la página web de errores.
  public static function errors() {
    if (empty($_SESSION['errors']) || !is_array($_SESSION['errors']))
      self::default_route();

    if (empty($_SESSION['errors']['message']) || empty($_SESSION['errors']['code']))
      $GLOBALS['messages'] -> errors('Set the error message and code', 400);

    http_response_code($_SESSION['errors']['code']);

    $head_title = 'Error';
    $token      = csrf::generate_token();
    $error      = $_SESSION['errors']['message'];

    unset($_SESSION['errors'], $_SESSION['messages']);

    require_once 'views/layouts/head.php';
    require_once 'views/layouts/navbar.php';
    require_once 'views/pages/errors.php';
    require_once 'views/layouts/footer.php';
  }

  // Renderiza la página web principal.
  public static function home() {
    global $messages;

    if (empty($_POST['search_submit'])) {
      $token    = csrf::generate_token();
      $messages = $messages -> messages();

      $blogModel = new blogModel();

      // Obtiene los artículos más valorados y recientes.
      $articles        = $blogModel -> popular_articles(5);
      $recent_articles = $blogModel -> recent_articles(self::num_articles);

      unset($blogModel);

      // Formatea los datos de los artículos durante la marcha.
      self::escape_articles($articles);
      self::escape_articles($recent_articles);

      require_once 'views/layouts/head.php';
      require_once 'views/layouts/navbar.php';
      require_once 'views/pages/home.php';
      require_once 'views/layouts/footer.php';
    }
    else {
      csrf::validate_token($_POST['csrf']);

      $query = self::validate_search($_POST);

      // Solicita una búsqueda de artículos.
      $messages -> redirect(NABU_ROUTES['search'] . '&q=' . urlencode($query));
    }
  }

  // Renderiza la página web para publicar artículos.
  public static function post() {
    if (!utils::session_exists())
      self::default_route();

    if (empty($_POST['post_submit'])) {
      $head_title = 'Publicar artículo';
      $token      = csrf::generate_token();
      $messages   = $GLOBALS['messages'] -> messages();

      require_once 'views/layouts/head.php';
      require_once 'views/layouts/navbar.php';
      require_once 'views/pages/post.php';
      require_once 'views/layouts/footer.php';
    }
    else {
      csrf::validate_token($_POST['csrf']);

      self::post_article($_POST);
    }
  }

  // Formatea los datos de los artículos.
  private static function escape_articles(&$articles) {
    foreach ($articles as &$article) {
      $article['title']    = utils::str_escape($article['title']);
      $article['synopsis'] = utils::str_escape($article['synopsis']);
      $article['author']   = utils::str_escape($article['author']);

      // Defina la ruta completa de la portada del artículo.
      if (empty($article['cover']))
        $article['cover'] = NABU_DEFAULT['cover'];
      else {
        // Valida si la imagen está disponible.
        if (file_exists(NABU_DIRECTORY['storage_covers'] . '/' . $article['cover']))
          $article['cover'] = NABU_DIRECTORY['covers'] . '/' . $article['cover'];
        else
          $article['cover'] = NABU_DEFAULT['cover'];
      }
    }

    unset($article);
  }

  // Renderiza la página web de todos los artículos publicados.
  public static function all_articles() {
    $head_title = 'Todos lo artículos';
    $token      = csrf::generate_token();

    $blogModel = new blogModel();

    // Obtiene el número total de artículos autorizados.
    $total = $blogModel -> count_articles();

    if ($total === false)
      self::default_route();

    // Página de resultado inicial.
    $page = 1;

    // Calcula el número total de páginas de resultados.
    $total_results = ceil($total/self::num_articles);

    if (isset($_GET['page']) && is_numeric($_GET['page']))
      $page = $_GET['page'];

    global $messages;

    $view = NABU_ROUTES['all_articles'];

    // Administra la paginación.
    if ($page < 1)
      $messages -> redirect($view);

    // Número total de resultados si no hay artículos publicados.
    if ($total_results == 0)
      $total_results = 1;

    if ($page > $total_results)
      $messages -> redirect($view . '&page=' . $total_results);

    // Calcula el número de artículos acumulados por paginación de resultados.
    $accumulation = ($page - 1) * self::num_articles;

    // Lista todos los artículos autorizados.
    $articles = $blogModel -> all_articles(self::num_articles, $accumulation);

    unset($blogModel, $total, $total_results, $accumulation);

    // Formatea los datos de los artículos durante la marcha.
    self::escape_articles($articles);

    require_once 'views/layouts/head.php';
    require_once 'views/layouts/navbar.php';
    require_once 'views/pages/all_articles.php';
    require_once 'views/layouts/footer.php';
  }

  // Renderiza la página web de artículos en espera de aprobación de un usuario.
  public static function sent() {
    if (!utils::session_exists())
      self::default_route();

    $head_title = 'Artículos enviados';
    $token      = csrf::generate_token();
    $messages   = $GLOBALS['messages'] -> messages();

    $blogModel = new blogModel();

    // Lista todos los artículos enviados.
    $articles = $blogModel -> sent_articles($_SESSION['user']['id']);

    // Formatea los datos de los artículos durante la marcha.
    foreach($articles as &$article) {
      $article['title']    = utils::str_escape($article['title']);
      $article['synopsis'] = utils::str_escape($article['synopsis']);
    }

    unset($blogModel, $article);

    require_once 'views/layouts/head.php';
    require_once 'views/layouts/navbar.php';
    require_once 'views/pages/sent.php';
    require_once 'views/layouts/footer.php';
  }

  // Renderiza la página web de resultados de búsqueda de artículos.
  public static function search() {
    if (empty($_GET['q']))
      self::default_route();

    $head_title = 'Búsqueda';
    $token      = csrf::generate_token();

    $query = self::validate_search($_GET);

    $blogModel = new blogModel();

    // Obtiene el número total de artículos buscados.
    $total = $blogModel -> count_search($query);

    if ($total === false)
      self::default_route();

    // Página de resultado inicial.
    $page = 1;

    // Calcula el número total de páginas de resultados.
    $total_results = ceil($total/self::num_articles);

    if (isset($_GET['page']) && is_numeric($_GET['page']))
      $page = $_GET['page'];

    global $messages;

    $view = NABU_ROUTES['search'] . '&q=' . urlencode($query);

    // Administra la paginación.
    if ($page < 1)
      $messages -> redirect($view);

    // Número total de resultados si no existen coincidencias de búsqueda.
    if ($total_results == 0)
      $total_results = 1;

    if ($page > $total_results)
      $messages -> redirect($view . '&page=' . $total_results);

    // Calcula el número de artículos acumulados por paginación de resultados.
    $accumulation = ($page - 1) * self::num_articles;

    // Lista de artículos con coincidencia de patrón de búsqueda.
    $articles = $blogModel -> search_articles($query, self::num_articles, $accumulation);

    unset($blogModel, $total, $total_results, $accumulation);

    $messages = $GLOBALS['messages'] -> messages();

    // Escapa todos los caracteres de una búsqueda.
    $query = utils::str_escape($query);

    // Formatea los datos de los artículos durante la marcha.
    self::escape_articles($articles);

    require_once 'views/layouts/head.php';
    require_once 'views/layouts/navbar.php';
    require_once 'views/pages/search.php';
    require_once 'views/layouts/footer.php';
  }

  // Renderiza la página web de un artículo.
  public static function article() {
    if (empty($_GET['slug']))
      self::default_route();

    $blogModel = new blogModel();
    $article = $blogModel -> get_article($_GET['slug']);

    if ($article == false)
      self::default_route();

    // Formatea los datos del artículo.
    $article['title']           = utils::str_escape($article['title']);
    $article['author']          = utils::str_escape($article['author']);
    $author_profile             = NABU_ROUTES['profile'] . '&user=' . urlencode($article['author_username']);
    $article['author_username'] = utils::str_escape($article['author_username']);

    // Define una descripción por defecto del autor.
    if (empty($article['author_description']))
      $article['author_description'] = 'Compartiendo conocimiento...';
    else
      $article['author_description'] = utils::str_escape($article['author_description']);

    $date_article = date_parse($article['date']);

    switch ($date_article['month']) {
      case 1:
        $month = 'Enero';
        break;
      case 2:
        $month = 'Febrero';
        break;
      case 3:
        $month = 'Marzo';
        break;
      case 4:
        $month = 'Abril';
        break;
      case 5:
        $month = 'Mayo';
        break;
      case 6:
        $month = 'Junio';
        break;
      case 7:
        $month = 'Julio';
        break;
      case 8:
        $month = 'Agosto';
        break;
      case 9:
        $month = 'Septiembre';
        break;
      case 10:
        $month = 'Octubre';
        break;
      case 11:
        $month = 'Noviembre';
        break;
      case 12:
        $month = 'Diciembre';
        break;
    }

    $article['date'] = $date_article['day'] . ' de ' . $month . ' del ' . $date_article['year'];

    // Defina la ruta completa de la portada del artículo.
    if (empty($article['cover']))
      $article['cover'] = NABU_DEFAULT['cover'];
    else {
      // Valida si la imagen está disponible.
      if (file_exists(NABU_DIRECTORY['storage_covers'] . '/' . $article['cover']))
        $article['cover'] = NABU_DIRECTORY['covers'] . '/' . $article['cover'];
      else
        $article['cover'] = NABU_DEFAULT['cover'];
    }

    // Defina la ruta completa del avatar del autor.
    if (empty($article['author_avatar']))
      $article['author_avatar'] = NABU_DEFAULT['avatars'];
    else {
      // Valida si la imagen está disponible.
      if (file_exists(NABU_DIRECTORY['storage_avatars'] . '/' . $article['author_avatar']))
        $article['author_avatar'] = NABU_DIRECTORY['avatars'] . '/' . $article['author_avatar'];
      else
        $article['author_avatar'] = NABU_DEFAULT['avatar'];
    }


    $Parsedown = new Parsedown();
    $Parsedown -> setSafeMode(true);

    // Convierte el artículo en Markdown a HTML.
    $article['content'] = $Parsedown -> text($article['content']);

    unset($blogModel, $Parsedown, $date_article, $month);

    $head_title = 'Artículo';
    $token      = csrf::generate_token();

    require_once 'views/layouts/head.php';
    require_once 'views/layouts/navbar.php';
    require_once 'views/pages/article.php';
    require_once 'views/layouts/comments.php';
    require_once 'views/layouts/footer.php';
  }

  // Renderiza la página web de artículos por categoría.
  public static function category() {
    $head_title = 'Categoría';
    $token      = csrf::generate_token();
    $articles   = array();

    require_once 'views/layouts/head.php';
    require_once 'views/layouts/navbar.php';
    require_once 'views/pages/category.php';
    require_once 'views/layouts/footer.php';
  }

  // Renderiza la página web de artículos favoritos.
  public static function favorites() {
    if (!utils::session_exists())
      self::default_route();

    $head_title = 'Favoritos';
    $token      = csrf::generate_token();
    $articles   = array();

    require_once 'views/layouts/head.php';
    require_once 'views/layouts/navbar.php';
    require_once 'views/pages/favorites.php';
    require_once 'views/layouts/footer.php';
  }

  // Valida los campos del formulario de búsqueda.
  private static function validate_search($form) {
    $validations = new validations(NABU_ROUTES['home']);

    $data = $validations -> validate_form($form, array(
      // 20210717-TÍTULO = 255 caracteres.
      array('q', 'exist' => true, 'max' => 246, 'trim_all' => true)
    ));

    return $data['q'];
  }

  // Valida los campos de publicación de un artículo y envía un artículo para su aprobación.
  private static function post_article($form) {
    $validations = new validations(NABU_ROUTES['post']);

    $data = $validations -> validate_form($form, array(
      array('title',    'exist' => true, 'max'      => 246, 'trim_all' => true),
      array('synopsis', 'exist' => true, 'trim_all' => true),
      array('content',  'exist' => true, 'max'      => NABU_DEFAULT['article_size'], 'trim' => true)
    ));

    $data['slug'] = utils::url_slug($data['title']);

    // Valida la longitud de la URL.
    $validations -> validate_form($data, array(
      array('slug', 'exist' => true)
    ));

    $blogModel = new blogModel();

    // Obtiene el id de un artículo dado su URL.
    $article = $blogModel -> article_id($data['slug']);

    global $messages;

    // Valida si el título del artículo es único en el día.
    if ($article) {
      $messages -> add_message('Por favor define un título diferente o espera máximo un día para enviar tu artículo');
      $messages -> redirect(NABU_ROUTES['post']);
    }

    $data['user_id'] = $_SESSION['user']['id'];

    // Registra el artículo en la base de datos..
    $blogModel -> save_article($data);

    $messages -> add_message('Tu artículo se ha enviado correctamente, en breve autorizaremos tu publicación');
    $messages -> redirect(NABU_ROUTES['sent']);
  }
}
